/*
MIT License 

Copyright (c) 2021 МГТУ им. Н.Э. Баумана, кафедра ИУ-6, Михаил Фетисов, 

https://bmstu.codes/lsx/simodo/loom
*/

#ifndef simodo_parser_AstBuilder_interface
#define simodo_parser_AstBuilder_interface

/*! \file AstBuilder_interface.h
    \brief Интерфейс построителя абстрактного синтаксического дерева.
    
    На самом деле он используется для построения абстрактного дерева операционной семантики simodo.
*/

#include "simodo/ast/Node.h"
#include "simodo/inout/token/Token.h"

#include <string>
#include <vector>
#include <map>

#define AST_BUILDER_DEBUG_no

namespace simodo::parser
{
    /*!
     * \brief Интерфейс строителя (ШП) абстрактного синтаксического дерева (АСД) (интерфейс).
     *
     * Интерфейс используется в парсере, в котором выполняются вызовы методов данного интерфейса.
     *
     * На самом деле АСД не обязательно должно быть деревом. Структура АСД должна быть
     * удобной для последующего выполнения семантического анализа и генерации кода.
     */
    class AstBuilder_interface
    {
    public:
        virtual ~AstBuilder_interface() = default; ///< Виртуальный деструктор

        /*!
         * \brief Метод вызывается парсером перед началом разбора
         * \return Если возвращается false, парсер прекращает разбор с ошибкой, иначе - продолжает
         */
        virtual bool onStart(const std::map<std::u16string,ast::Node> & handlers) = 0;

#ifdef AST_BUILDER_DEBUG
        /*!
         * \brief Метод вызывается парсером при выполнении свёртки
         *
         * Метод вызывается, когда выполняется свёртка состояний.
         *
         * \param state_no      Номер состояния
         * \param rule_no       Номер правила
         * \param production    Токен продукции, на которую заменяется шаблон в стеке состояний парсера
         * \param pattern       Шаблон (набор токенов), который заменяется на продукцию в стеке состояний парсера
         * \param action        АСД для интерпретатора для формирования фрагмента АСД по данной продукции
         * \param back_state_no Номер состояния возврата после свёртки
         * \param shift_state_no Номер состояния перехода после свёртки
         * \return Если возвращается false, парсер прекращает разбор с ошибкой, иначе - продолжает
         */
        virtual bool onProduction(size_t state_no,
                                  size_t rule_no,
                                  const inout::Token & production,
                                  const std::vector<inout::Token> & pattern,
                                  const ast::Node & action,
                                  size_t back_state_no,
                                  size_t shift_state_no) = 0;

        virtual bool onShift(size_t state_no, const inout::Lexeme & t, size_t column_no, size_t shift_state_no) = 0;
#else
        /*!
         * \brief Метод вызывается парсером при выполнении свёртки
         *
         * Метод вызывается, когда выполняется свёртка состояний.
         *
         * \param production    Токен продукции, на которую заменяется шаблон в стеке состояний парсера
         * \param pattern       Шаблон (набор токенов), который заменяется на продукцию в стеке состояний парсера
         * \param action        АСД для интерпретатора для формирования фрагмента АСД по данной продукции
         * \return Если возвращается false, парсер прекращает разбор с ошибкой, иначе - продолжает
         */
        virtual bool onProduction(const inout::Token & production,
                                  const std::vector<inout::Token> & pattern,
                                  const ast::Node & action) = 0;
#endif

        /*!
         * \brief Метод вызывается парсером при получении очередного токена
         * \param t Токен, полученный парсером из входного потока
         */
        virtual void onTerminal(const inout::Token & t) = 0;

        /*!
         * \brief Метод вызывается парсером после завершения разбора текста
         *
         * Предполагается, что при вызове данного метода и при наличии признака успешности
         * разбора текста, нужно завершить формирование АСД.
         *
         * \param success   Признак успешности разбора текста
         * \return Если возвращается false, парсер прекращает разбор с ошибкой, иначе - продолжает
         */
        virtual bool onFinish(bool success, const std::map<std::u16string,ast::Node> & handlers) = 0;
    };

    /*!
     * \brief Класс-заглушка: генератор АСД, который ничего не генерит
     */
    class AstBuilder_null: public AstBuilder_interface
    {
    public:
        /*!
         * \brief Метод вызывается парсером перед началом разбора
         * \return Если возвращается false, парсер прекращает разбор с ошибкой, иначе - продолжает
         */
        virtual bool onStart(const std::map<std::u16string,ast::Node> & ) override { return true; }

#ifdef AST_BUILDER_DEBUG
        /*!
         * \brief Метод вызывается парсером при выполнении свёртки
         * \return Если возвращается false, парсер прекращает разбор с ошибкой, иначе - продолжает
         */
        virtual bool onProduction(size_t , size_t , const inout::Token & , const std::vector<inout::Token> & , 
                                  const ast::Node & , size_t , size_t ) override { return true; }

        virtual bool onShift(size_t , const inout::Lexeme & , size_t , size_t ) override { return true; }
#else
        /*!
         * \brief Метод вызывается парсером при выполнении свёртки
         * \return Если возвращается false, парсер прекращает разбор с ошибкой, иначе - продолжает
         */
        virtual bool onProduction(const inout::Token & , const std::vector<inout::Token> & , 
                                  const ast::Node & ) override { return true; }
#endif
        /*!
         * \brief Метод вызывается парсером при получении очередного токена
         * \return Если возвращается false, парсер прекращает разбор с ошибкой, иначе - продолжает
         */
        virtual void onTerminal(const inout::Token & ) override {}

        /*!
         * \brief Метод вызывается парсером после завершения разбора текста
         * \return Если возвращается false, парсер прекращает разбор с ошибкой, иначе - продолжает
         */
        virtual bool onFinish(bool, const std::map<std::u16string,ast::Node> & ) override { return true; }
    };

}

#endif // simodo_parser_AstBuilder_interface
